//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package org_dao

import (
	"context"

	"atomgit.com/openlinksaas-org/api-server/dao/db_ns"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/org_forum_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type OrgForumPermDbItem struct {
	AllowCreateThreadForAll bool     `bson:"allowCreateThreadForAll"`
	CreateThreadUserIdList  []string `bson:"createThreadUserIdList"`
	AllowReplyThreadForAll  bool     `bson:"allowReplyThreadForAll"`
	ReplyThreadUserIdList   []string `bson:"replyThreadUserIdList"`
}

type OrgForumInfoDbItem struct {
	ForumId      string             `bson:"_id"`
	ForumName    string             `bson:"forumName"`
	OrgId        string             `bson:"orgId"`
	Weight       uint32             `bson:"weight"`
	FsId         string             `bson:"fsId"`
	ThreadCount  uint32             `bson:"threadCount"`
	TimeStamp    int64              `bson:"timeStamp"`
	OrgForumPerm OrgForumPermDbItem `bson:"orgForumPerm"`
}

func (item *OrgForumInfoDbItem) ToOrgForumInfo(memberUserId string) *org_forum_api.OrgForumInfo {
	createThread := false
	replyThread := false
	if item.OrgForumPerm.AllowCreateThreadForAll {
		createThread = true
	}
	if !createThread {
		for _, userId := range item.OrgForumPerm.CreateThreadUserIdList {
			if userId == memberUserId {
				createThread = true
				break
			}
		}
	}

	if item.OrgForumPerm.AllowReplyThreadForAll {
		replyThread = true
	}
	if !replyThread {
		for _, userId := range item.OrgForumPerm.ReplyThreadUserIdList {
			if userId == memberUserId {
				replyThread = true
				break
			}
		}
	}

	return &org_forum_api.OrgForumInfo{
		ForumId:     item.ForumId,
		ForumName:   item.ForumName,
		OrgId:       item.OrgId,
		Weight:      item.Weight,
		FsId:        item.FsId,
		ThreadCount: item.ThreadCount,
		OrgForumPerm: &org_forum_api.OrgForumPerm{
			AllowCreateThreadForAll: item.OrgForumPerm.AllowCreateThreadForAll,
			CreateThreadUserIdList:  item.OrgForumPerm.CreateThreadUserIdList,
			AllowReplyThreadForAll:  item.OrgForumPerm.AllowReplyThreadForAll,
			ReplyThreadUserIdList:   item.OrgForumPerm.ReplyThreadUserIdList,
		},
		UserPerm: &org_forum_api.UserPerm{
			CreateThread: createThread,
			ReplyThread:  replyThread,
		},
	}
}

type _ForumDao struct {
	mc *mongo.Collection
}

func newForumDao(db *mongo.Database) (*_ForumDao, error) {
	mc := db.Collection(db_ns.DB_NS_ORG + "forum")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"orgId", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_ForumDao{mc: mc}, nil
}

func (db *_ForumDao) Insert(ctx context.Context, dbItem *OrgForumInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_ForumDao) Exist(ctx context.Context, orgId, forumId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"orgId": orgId, "_id": forumId})
	return count > 0, err
}

func (db *_ForumDao) Get(ctx context.Context, orgId, forumId string) (*OrgForumInfoDbItem, error) {
	retItem := &OrgForumInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"orgId": orgId, "_id": forumId}).Decode(retItem)
	return retItem, err
}

func (db *_ForumDao) Remove(ctx context.Context, orgId, forumId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"orgId": orgId, "_id": forumId})
	return err
}

func (db *_ForumDao) RemoveByOrg(ctx context.Context, orgId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"orgId": orgId})
	return err
}

func (db *_ForumDao) List(ctx context.Context, orgId string) ([]*OrgForumInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"orgId": orgId}, options.Find().SetSort(bson.D{{"weight", -1}, {"timeStamp", -1}}))
	if err != nil {
		return nil, err
	}
	retList := []*OrgForumInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_ForumDao) ListById(ctx context.Context, orgId string, forumIdList []string) ([]*OrgForumInfoDbItem, error) {
	if len(forumIdList) == 0 {
		return []*OrgForumInfoDbItem{}, nil
	}
	cursor, err := db.mc.Find(ctx, bson.M{"orgId": orgId, "_id": bson.M{"$in": forumIdList}})
	if err != nil {
		return nil, err
	}
	retList := []*OrgForumInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_ForumDao) Update(ctx context.Context, orgId, forumId, forumName string, weight uint32, orgPerm *OrgForumPermDbItem, timeStamp int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"orgId": orgId, "_id": forumId},
		bson.M{"$set": bson.M{
			"forumName":    forumName,
			"weight":       weight,
			"orgForumPerm": orgPerm,
			"timeStamp":    timeStamp,
		}})
	return err
}

func (db *_ForumDao) UpdateThreadCount(ctx context.Context, orgId, forumId string, count uint32) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"orgId": orgId, "_id": forumId},
		bson.M{"$set": bson.M{
			"threadCount": count,
		}})
	return err
}

// 升级脚本中使用
func (db *_ForumDao) FixForumPerm(ctx context.Context) error {
	_, err := db.mc.UpdateMany(ctx, bson.M{},
		bson.M{"$set": bson.M{
			"orgForumPerm": &OrgForumPermDbItem{
				AllowCreateThreadForAll: true,
				CreateThreadUserIdList:  []string{},
				AllowReplyThreadForAll:  true,
				ReplyThreadUserIdList:   []string{},
			},
		}})
	return err
}
